Import("env")
Import("base_toolchain_bin")
Import("use_libunwind")

import os
import sys

import SCons

# multiple compilation databases is not supported by ninja
if env.GetOption("ninja") == "disabled":
    mongo_tidy_test_env = env.Clone()

    mongo_tidy_test_env.Append(
        CPPPATH=[
            ".",
            "#src",
            "#src/third_party/boost",
        ],
    )

    # These test files will purposefully be error prone, so we can disable warnings any warnings we expect
    # to see.
    mongo_tidy_test_env.Append(
        CCFLAGS=[
            "-Wno-unused-but-set-parameter",
        ],
    )

    # This list represents the test source files, which should contain a single issue which will be flagged
    # by a clang tidy check. The issue should be isolated in as minimal way as possible.
    tests = [
        "test_MongoHeaderBracketCheck.cpp",
        "test_MongoVolatileCheck.cpp",
        "test_MongoUninterruptibleLockGuardCheck.cpp",
        "test_MongoUninterruptibleLockGuardCheckForOpCtxMember.cpp",
        "test_MongoCctypeCheck.cpp",
        "test_MongoConfigHeaderCheck.cpp",
        "test_MongoCxx20BannedIncludesCheck.cpp",
        "test_MongoCxx20StdChronoCheck.cpp",
        "test_MongoStdOptionalCheck.cpp",
        "test_MongoTraceCheck.cpp",
        "test_MongoStdAtomicCheck.cpp",
        "test_MongoAssertCheck.cpp",
        "test_MongoFCVConstantCheck.cpp",
        "test_MongoUnstructuredLogCheck.cpp",
        "test_MongoCollectionShardingRuntimeCheck.cpp",
        "test_MongoMacroDefinitionLeaksCheck.cpp",
        "test_MongoRandCheck.cpp",
        "test_MongoRWMutexCheck.cpp",
        "test_MongoPolyFillCheck.cpp",
        "test_MongoNoUniqueAddressCheck.cpp",
        "test_MongoStringDataConstRefCheck1.cpp",
        "test_MongoStringDataConstRefCheck2.cpp",
        "test_MongoStringDataConstRefCheck3.cpp",
        "test_MongoInvariantStatusIsOKCheck.cpp",
    ]

    # So that we can do fast runs, we will generate a separate compilation database file for each
    # unittest. To keep things simple we will name the compilation database file after the test.
    # We need to create separate environments here because compilation database acts on the current
    # environment.
    test_objs = []
    compilation_dbs = []
    for test in tests:
        test_env = mongo_tidy_test_env.Clone(COMPDB_IGNORE_BAZEL=True)
        compilation_dbs += test_env.CompilationDatabase(
            os.path.splitext(os.path.basename(test))[0] + "/compile_commands.json"
        )
        test_objs += test_env.Object(test)

    # Building a program binary may not be necessary but it does validate the code and tie it together.
    test_prog = mongo_tidy_test_env.BazelProgram(
        target="MongoTidyCheck_test",
        source=[],
        LIBDEPS_NO_INHERIT=[],
    )

    # Here we setup the test execution. The test will pythons built in unittest framework
    # to execute clang tidy for each test source file from the list above.
    test = mongo_tidy_test_env.Command(
        target="run_MongoTidyCheck_test",
        source=[
            "MongoTidyCheck_unittest.py",
            str(base_toolchain_bin / "clang-tidy"),
            "#$BAZEL_OUT_DIR/src/mongo/tools/mongo_tidy_checks/libmongo_tidy_checks.so",
        ]
        + compilation_dbs,
        action=SCons.Action.Action(
            " ".join(
                [
                    sys.executable,
                    "${SOURCES[0]}",
                    "--clang-tidy-path=${SOURCES[1]}",
                    "--mongo-tidy-module=${SOURCES[2]}",
                    '${["--test-compiledbs=%s" % src for src in SOURCES[3:]]}',
                    f"{'' if mongo_tidy_test_env.Verbose() else '2> /dev/null'}",
                ]
            ),
            "" if mongo_tidy_test_env.Verbose() else "Runnning mongo tidy checks unittests.",
        ),
    )

    mongo_tidy_test_env.Alias("+mongo-tidy-tests", test)
    mongo_tidy_test_env.Depends(test, test_prog)
